﻿#region File Description
//-----------------------------------------------------------------------------
// ScreenManager.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
#endregion

namespace DungDungShit
{
    public enum ScreenType { Game, Editor };
    /// <summary>
    /// The screen manager is a component which manages one or more GameScreen
    /// instances. It maintains a stack of screens, calls their Update and Draw
    /// methods at the appropriate times, and automatically routes input to the
    /// topmost active screen.
    /// </summary>
    public class ScreenManager : DrawableGameComponent
    {
        #region Fields

        public static Random r = new Random();

        List<Screen> screens = new List<Screen>();
        List<Screen> screensToUpdate = new List<Screen>();

        InputState input = new InputState();

        SpriteBatch spriteBatch;
        SpriteFont font, smallFont;
        Texture2D blankTexture;

        /* Player Textrues */
        Texture2D heartTexture;
        Texture2D compassTexture;
        Texture2D playerStandTexture;
        Texture2D playerLeftTexture, playerRightTexture, playerUpTexture, playerDownTexture;

        /* People Textures */
        Texture2D[] peopleTexture = new Texture2D[4];

        /* Tile Textures */
        Texture2D escapeTexture;
        Texture2D normalTexture;
        Texture2D wallTexture;
        Texture2D spikeTexture;
        Texture2D fireTexture;

        Texture2D backTexture;
        Texture2D titleTexture;

        SoundEffect bgm;

        bool isInitialized;
        bool traceEnabled;

        #endregion

        #region Properties


        /// <summary>
        /// A default SpriteBatch shared by all the screens. This saves
        /// each screen having to bother creating their own local instance.
        /// </summary>
        public SpriteBatch SpriteBatch
        { get { return spriteBatch; } }


        /// <summary>
        /// A default font shared by all the screens. This saves
        /// each screen having to bother loading their own local copy.
        /// </summary>
        public SpriteFont Font
        { get { return font; } }
        public SpriteFont SmallFont
        { get { return smallFont; } }

        public Texture2D BlankTexture { get { return blankTexture; } }
        public Texture2D HeartTexture { get { return heartTexture; } }
        public Texture2D CompassTexture { get { return compassTexture; } }

        public Texture2D PeopleTexture(int i)
        {
            return peopleTexture[i];
        }

        public SoundEffect BGM { get { return bgm; } }

        public Texture2D TitleTexture { get { return titleTexture; } }

        /// <summary> 간단하게 char 하나에서 텍스쳐를 얻어옴 </summary>
        public Texture2D GetTextureFromChar(char c)
        {
            switch (c)
            {
                case 't': return titleTexture;
                case 'E': return escapeTexture;
                case '@': return normalTexture;
                case '$': return fireTexture;
                case '^': return spikeTexture;
                case 'h': return heartTexture;
                case 'c': return compassTexture;
                case '_': return blankTexture;
                case 'i': return playerUpTexture;
                case 'j': return playerLeftTexture;
                case 'k': return playerDownTexture;
                case 'l': return playerRightTexture;
                case 's': return playerStandTexture;
                case ' ': return normalTexture;
                case '1': return wallTexture;
                default: return normalTexture;
            }
        }

        /// <summary>
        /// If true, the manager prints out a list of all the screens
        /// each time it is updated. This can be useful for making sure
        /// everything is being added and removed at the right times.
        /// </summary>
        public bool TraceEnabled
        {
            get { return traceEnabled; }
            set { traceEnabled = value; }
        }


        #endregion

        #region Initialization


        /// <summary>
        /// Constructs a new screen manager component.
        /// </summary>
        public ScreenManager(Game game)
            : base(game)
        {
            // we must set EnabledGestures before we can query for them, but
            // we don't assume the game wants to read them.
            //TouchPanel.EnabledGestures = GestureType.None;
        }
        /// <summary>
        /// Initializes the screen manager component.
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();

            isInitialized = true;
        }
        /// <summary>
        /// Load your graphics content.
        /// </summary>
        protected override void LoadContent()
        {
            // Load content belonging to the screen manager.
            ContentManager content = Game.Content;

            spriteBatch = new SpriteBatch(GraphicsDevice);
            font = content.Load<SpriteFont>("Font");
            smallFont = content.Load<SpriteFont>("SmallFont");
            blankTexture = content.Load<Texture2D>("blank");

            heartTexture = content.Load<Texture2D>("heart");
            compassTexture = content.Load<Texture2D>("compass");
            playerStandTexture = content.Load<Texture2D>("Player/stand");
            playerLeftTexture = content.Load<Texture2D>("Player/left");
            playerRightTexture = content.Load<Texture2D>("Player/right");
            playerUpTexture = content.Load<Texture2D>("Player/up");
            playerDownTexture = content.Load<Texture2D>("Player/down");

            normalTexture = content.Load<Texture2D>("Tiles/normal");
            wallTexture = content.Load<Texture2D>("Tiles/emptywall");
            spikeTexture = content.Load<Texture2D>("Tiles/spike");
            fireTexture = content.Load<Texture2D>("Tiles/fire");
            escapeTexture = content.Load<Texture2D>("Tiles/escape");

            titleTexture = content.Load<Texture2D>("title");

            peopleTexture[0] = content.Load<Texture2D>("People/man");
            peopleTexture[1] = content.Load<Texture2D>("People/rich_man");
            peopleTexture[2] = content.Load<Texture2D>("People/woman");
            peopleTexture[3] = content.Load<Texture2D>("People/rich_woman");

            bgm = content.Load<SoundEffect>("bgm");

            // Tell each of the screens to load their content.
            foreach (Screen screen in screens)
            {
                screen.LoadContent();
            }
        }


        /// <summary>
        /// Unload your graphics content.
        /// </summary>
        protected override void UnloadContent()
        {
            // Tell each of the screens to unload their content.
            foreach (Screen screen in screens)
            {
                screen.UnloadContent();
            }
        }


        #endregion

        #region Update and Draw


        /// <summary>
        /// Allows each screen to run logic.
        /// </summary>
        public override void Update(GameTime gameTime)
        {
            // Read the keyboard and gamepad.
            input.Update();

            // Make a copy of the master screen list, to avoid confusion if
            // the process of updating one screen adds or removes others.
            screensToUpdate.Clear();

            foreach (Screen screen in screens)
                screensToUpdate.Add(screen);

            bool otherScreenHasFocus = !Game.IsActive;
            bool coveredByOtherScreen = false;

            // Loop as long as there are screens waiting to be updated.
            while (screensToUpdate.Count > 0)
            {
                // Pop the topmost screen off the waiting list.
                Screen screen = screensToUpdate[screensToUpdate.Count - 1];

                screensToUpdate.RemoveAt(screensToUpdate.Count - 1);

                // Update the screen.
                screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

                if (screen.ScreenState == ScreenState.TransitionOn ||
                    screen.ScreenState == ScreenState.Active)
                {
                    // If this is the first active screen we came across,
                    // give it a chance to handle input.
                    if (!otherScreenHasFocus)
                    {
                        screen.HandleInput(input);

                        otherScreenHasFocus = true;
                    }

                    // If this is an active non-popup, inform any subsequent
                    // screens that they are covered by it.
                    if (!screen.IsPopup)
                        coveredByOtherScreen = true;
                }
            }

            // Print debug trace?
            if (traceEnabled)
                TraceScreens();
        }


        /// <summary>
        /// Prints a list of all the screens, for debugging.
        /// </summary>
        void TraceScreens()
        {
            List<string> screenNames = new List<string>();

            foreach (Screen screen in screens)
                screenNames.Add(screen.GetType().Name);

            Debug.WriteLine(string.Join(", ", screenNames.ToArray()));
        }


        /// <summary>
        /// Tells each screen to draw itself.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            foreach (Screen screen in screens)
            {
                if (screen.ScreenState == ScreenState.Hidden)
                    continue;

                screen.Draw(gameTime);
            }
        }


        #endregion

        #region Public Methods


        /// <summary>
        /// Adds a new screen to the screen manager.
        /// </summary>
        public void AddScreen(Screen screen)
        {
            screen.ScreenManager = this;
            screen.IsExiting = false;

            // If we have a graphics device, tell the screen to load content.
            if (isInitialized)
            {
                screen.LoadContent();
            }

            screens.Add(screen);
        }


        /// <summary>
        /// Removes a screen from the screen manager. You should normally
        /// use GameScreen.ExitScreen instead of calling this directly, so
        /// the screen can gradually transition off rather than just being
        /// instantly removed.
        /// </summary>
        public void RemoveScreen(Screen screen)
        {
            // If we have a graphics device, tell the screen to unload content.
            if (isInitialized)
            {
                screen.UnloadContent();
            }

            screens.Remove(screen);
            screensToUpdate.Remove(screen);

            // if there is a screen still in the manager, update TouchPanel
            // to respond to gestures that screen is interested in.
            /*
            if (screens.Count > 0)
            {
                TouchPanel.EnabledGestures = screens[screens.Count - 1].EnabledGestures;
            }
            */
        }


        /// <summary>
        /// Expose an array holding all the screens. We return a copy rather
        /// than the real master list, because screens should only ever be added
        /// or removed using the AddScreen and RemoveScreen methods.
        /// </summary>
        public Screen[] GetScreens()
        {
            return screens.ToArray();
        }


        /// <summary>
        /// Helper draws a translucent black fullscreen sprite, used for fading
        /// screens in and out, and for darkening the background behind popups.
        /// </summary>
        public void FadeBackBufferToBlack(float alpha)
        {
            Viewport viewport = GraphicsDevice.Viewport;

            spriteBatch.Begin();

            spriteBatch.Draw(blankTexture,
                             new Rectangle(0, 0, viewport.Width, viewport.Height),
                             Color.Black * alpha);

            spriteBatch.End();
        }


        #endregion
    }
}
